﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using DotNetCommon;
using DotNetCommon.Data;
using DotNetCommon.Extensions;

namespace ConsoleTest
{
    public class Program
    {
        static void Main(string[] args)
        {
            //简单类型转换(比对4种方式: src/dotnetcommon/automapper/jsonserial )
            Test1();
            //循环引用(比对2种方式: dotnetcommon/automapper)
            //Test3();
            //嵌套(比对4种方式: src/dotnetcommon/automapper/jsonserial )
            //Test4();
            //树状结构(比对3种方式: dotnetcommon/automapper/jsonserial)
            //Test5();
            Console.WriteLine("比对完成!");
            Console.Read();
        }

        #region 简单转换 Person => PersonDto 同类型属性17个 无嵌套类型
        private static void Test1()
        {
            Console.WriteLine();

            var person = new Person()
            {
                Id = 1,
                Name = "Test",
                Addr = "天明路",
                Age = 18,
                Description = "描述",
                Email = "123456789@qq.com",
                IdentityNo = "410123200001021234",
                Intro = "个性签名",
                Nick = "昵称",
                Phone = "15012345678",
                Picture = "https://iconfont.alicdn.com/t/ff73b7fb-7199-4356-8d10-5dd133bac7a9.png",
                Birth = DateTime.Parse("2000-01-02"),
                QQ = "123456789",
                Score = 98.5,
                Sex = EnumSex.Male,
                WeiXin = "weixinname",
                Books = new List<string> { "语文", "数学" },
            };

            var list = new List<Person>();
            for (var i = 0; i < 100; i++) list.Add(person.ToJson().ToObject<Person>());

            //手写代码
            Console.WriteLine();
            Console.WriteLine($"SrcMapper---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestSrcMapper(list);

            //DotNetCommon 使用编译表达式
            Console.WriteLine();
            Console.WriteLine($"DotNetCommon---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestDotNetCommon(list, false);

            //AutoMapper
            Console.WriteLine();
            Console.WriteLine($"AutoMapper---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestAutoMapper(list);

            //JsonSerial
            Console.WriteLine();
            Console.WriteLine($"JsonSerial---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestJsonSerial(list);
        }
        static void TestSrcMapper(List<Person> list)
        {
            list.Select(inst => new PersonDto { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, }).ToList();
            var st = new Stopwatch();
            st.Start();
            list.Select(inst => new PersonDto { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, }).ToList();
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Select(inst => new PersonDto { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Select(inst => new PersonDto { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Select(inst => new PersonDto { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestDotNetCommon(List<Person> list, bool containsRepeatReference = false)
        {
            list.Mapper<List<PersonDto>>(containsRepeatReference);
            var st = new Stopwatch();
            st.Start();
            list.Mapper<List<PersonDto>>(containsRepeatReference);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Mapper<List<PersonDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Mapper<List<PersonDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Mapper<List<PersonDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestAutoMapper(List<Person> list)
        {
            var config = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap<Person, PersonDto>());
            var mapper = new AutoMapper.Mapper(config);
            mapper.Map<List<PersonDto>>(list);

            var st = new Stopwatch();
            st.Start();
            mapper.Map<List<PersonDto>>(list);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                mapper.Map<List<PersonDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                mapper.Map<List<PersonDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                mapper.Map<List<PersonDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestJsonSerial(List<Person> list)
        {
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<PersonDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));

            var st = new Stopwatch();
            st.Start();
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<PersonDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<PersonDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<PersonDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<PersonDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }
        #endregion

        #region 循环引用
        public static void Test3()
        {
            var list = new List<PersonExt>();
            for (var i = 0; i < 100; i++)
            {
                var inst = new PersonExt
                {
                    Id = 1,
                    Name = "Test",
                    Addr = "天明路",
                    Age = 18,
                    Description = "描述",
                    Email = "123456789@qq.com",
                    IdentityNo = "410123200001021234",
                    Intro = "个性签名",
                    Nick = "昵称",
                    Phone = "15012345678",
                    Picture = "https://iconfont.alicdn.com/t/ff73b7fb-7199-4356-8d10-5dd133bac7a9.png",
                    Birth = DateTime.Parse("2000-01-02"),
                    QQ = "123456789",
                    Score = 98.5,
                    Sex = EnumSex.Male,
                    WeiXin = "weixinname",
                    Books = new List<string> { "语文", "数学" },
                };
                inst.Self = inst;
                list.Add(inst);
            };

            //DotNetCommon 使用编译表达式
            Console.WriteLine();
            Console.WriteLine($"DotNetCommon---------------------------List<PersonExt>[Count=100] => List<PersonDtoExt>-------------------------------");
            TestDotNetCommonCircle(list);

            //AutoMapper
            Console.WriteLine();
            Console.WriteLine($"AutoMapper---------------------------List<PersonExt>[Count=100] => List<PersonDtoExt>-------------------------------");
            TestAutoMapperCircle(list);
        }

        static void TestDotNetCommonCircle(List<PersonExt> list)
        {
            list.Mapper<List<PersonExtDto>>();
            var st = new Stopwatch();
            st.Start();
            list.Mapper<List<PersonExtDto>>();
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Mapper<List<PersonExtDto>>();
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Mapper<List<PersonExtDto>>();
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Mapper<List<PersonExtDto>>();
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestAutoMapperCircle(List<PersonExt> list)
        {
            var config = new AutoMapper.MapperConfiguration(cfg => cfg.CreateMap<PersonExt, PersonExtDto>());
            var mapper = new AutoMapper.Mapper(config);
            mapper.Map<List<PersonExtDto>>(list);

            var st = new Stopwatch();
            st.Start();
            mapper.Map<List<PersonExtDto>>(list);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                mapper.Map<List<PersonExtDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                mapper.Map<List<PersonExtDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                mapper.Map<List<PersonExtDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }
        #endregion

        #region 嵌套类型转换
        public static void Test4()
        {
            var list = new List<Outer>();
            for (var i = 0; i < 100; i++)
            {
                var inst = new Outer
                {
                    Id = 1,
                    Name = "Test",
                    Addr = "天明路",
                    Age = 18,
                    Description = "描述",
                    Email = "123456789@qq.com",
                    IdentityNo = "410123200001021234",
                    Intro = "个性签名",
                    Nick = "昵称",
                    Phone = "15012345678",
                    Picture = "https://iconfont.alicdn.com/t/ff73b7fb-7199-4356-8d10-5dd133bac7a9.png",
                    Birth = DateTime.Parse("2000-01-02"),
                    QQ = "123456789",
                    Score = 98.5,
                    Sex = EnumSex.Male,
                    WeiXin = "weixinname",
                    Books = new List<string> { "语文", "数学" },
                    Inner = new Inner
                    {
                        Id = 1,
                        Addr = "提阿尼公路",
                        Age = 18,
                        Name = "Test",
                        Score = 98.5
                    }
                };
                list.Add(inst);
            };

            //手写代码
            Console.WriteLine();
            Console.WriteLine($"SrcMapper---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestSrcMapperNest(list);

            //DotNetCommon 使用编译表达式
            Console.WriteLine();
            Console.WriteLine($"DotNetCommon---------------------------List<Outer>[Count=100] => List<OuterDto>-------------------------------");
            TestDotNetCommonNest(list, false);

            //AutoMapper
            Console.WriteLine();
            Console.WriteLine($"AutoMapper---------------------------List<Outer>[Count=100] => List<OuterDto>-------------------------------");
            TestAutoMapperNest(list);

            //JsonSerial
            Console.WriteLine();
            Console.WriteLine($"JsonSerial---------------------------List<Person>[Count=100] => List<PersonDto>-------------------------------");
            TestJsonSerialNest(list);
        }

        static void TestSrcMapperNest(List<Outer> list)
        {
            list.Select(inst => new OuterDto
            { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, Inner = new InnerDto { Id = inst.Inner.Id, Addr = inst.Inner.Addr, Age = inst.Inner.Age, Name = inst.Inner.Name, Score = inst.Inner.Score } }).ToList();
            var st = new Stopwatch();
            st.Start();
            list.Select(inst => new OuterDto
            { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, Inner = new InnerDto { Id = inst.Inner.Id, Addr = inst.Inner.Addr, Age = inst.Inner.Age, Name = inst.Inner.Name, Score = inst.Inner.Score } }).ToList();
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Select(inst => new OuterDto
                { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, Inner = new InnerDto { Id = inst.Inner.Id, Addr = inst.Inner.Addr, Age = inst.Inner.Age, Name = inst.Inner.Name, Score = inst.Inner.Score } }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Select(inst => new OuterDto
                { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, Inner = new InnerDto { Id = inst.Inner.Id, Addr = inst.Inner.Addr, Age = inst.Inner.Age, Name = inst.Inner.Name, Score = inst.Inner.Score } }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Select(inst => new OuterDto
                { Addr = inst.Addr, WeiXin = inst.WeiXin, Sex = inst.Sex, Score = inst.Score, Age = inst.Age, Birth = inst.Birth, Books = inst.Books, Description = inst.Description, Email = inst.Email, Id = inst.Id, IdentityNo = inst.IdentityNo, Intro = inst.Intro, Name = inst.Name, Nick = inst.Nick, Phone = inst.Phone, Picture = inst.Picture, QQ = inst.QQ, Inner = new InnerDto { Id = inst.Inner.Id, Addr = inst.Inner.Addr, Age = inst.Inner.Age, Name = inst.Inner.Name, Score = inst.Inner.Score } }).ToList();
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestDotNetCommonNest(List<Outer> list, bool containsRepeatReference)
        {
            list.Mapper<List<OuterDto>>(containsRepeatReference);
            var st = new Stopwatch();
            st.Start();
            list.Mapper<List<OuterDto>>(containsRepeatReference);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Mapper<List<OuterDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Mapper<List<OuterDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Mapper<List<OuterDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestAutoMapperNest(List<Outer> list)
        {
            var config = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Outer, OuterDto>();
                cfg.CreateMap<Inner, InnerDto>();
            });
            var mapper = new AutoMapper.Mapper(config);
            mapper.Map<List<OuterDto>>(list);

            var st = new Stopwatch();
            st.Start();
            mapper.Map<List<OuterDto>>(list);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                mapper.Map<List<OuterDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                mapper.Map<List<OuterDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                mapper.Map<List<OuterDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestJsonSerialNest(List<Outer> list)
        {
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<OuterDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));

            var st = new Stopwatch();
            st.Start();
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<OuterDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OuterDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OuterDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OuterDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }
        #endregion

        #region 树状结构
        public static void Test5()
        {
            List<OrgNode> tmpList = null;
            #region 构造平铺的数据
            tmpList = new List<OrgNode>()
            {
                new OrgNode()
                {
                    Id=1,
                    Name="河南",
                    Pwd="henan",
                    CreatetTime=DateTime.Now,
                    Active=null
                },
                new OrgNode()
                {
                    Id=2,
                    Name="河北",
                    Pwd="hebei",
                    CreatetTime=DateTime.Now,
                    Active=null
                },
                new OrgNode()
                {
                    Id=3,
                    Name="郑州",
                    ParentId=1,
                    Active=true,
                    CreatetTime=DateTime.Now,
                    Pwd="zhengzhou"
                },
                new OrgNode()
                {
                    Id=4,
                    Name="开封",
                    ParentId=1,
                    Active=true,
                    CreatetTime=DateTime.Now,
                    Pwd="kaifeng"
                },
                new OrgNode()
                {
                    Id=5,
                    Name="中原区",
                    ParentId=3,
                    Active=true,
                    CreatetTime=DateTime.Now,
                    Pwd="zhongyuanqu"
                },
                new OrgNode()
                {
                    Id=6,
                    Name="金水区",
                    ParentId=3,
                    Active=true,
                    CreatetTime=DateTime.Now,
                    Pwd="jinshuiqu"
                },
                new OrgNode()
                {
                    Id=7,
                    Name="文化路",
                    ParentId=6,
                    Active=true,
                    CreatetTime=DateTime.Now,
                    Pwd="wenhualu"
                }
            };
            #endregion
            var list = tmpList.FetchToTree(o => o.Id, o => o.ParentId, i => i.Children);

            //DotNetCommon 使用编译表达式
            Console.WriteLine();
            Console.WriteLine($"DotNetCommon---------------------------List<OrgNode>[Count=100] => List<OrgNodeDto>-------------------------------");
            TestDotNetCommonTree(list, false);

            //AutoMapper
            Console.WriteLine();
            Console.WriteLine($"AutoMapper---------------------------List<OrgNode>[Count=100] => List<OrgNodeDto>-------------------------------");
            TestAutoMapperTree(list);

            //JsonSerial
            Console.WriteLine();
            Console.WriteLine($"JsonSerial---------------------------List<OrgNode>[Count=100] => List<OrgNodeDto>-------------------------------");
            TestJsonSerialTree(list);

        }

        static void TestDotNetCommonTree(List<OrgNode> list, bool containsRepeatReference)
        {
            list.Mapper<List<OrgNodeDto>>(containsRepeatReference);
            var st = new Stopwatch();
            st.Start();
            list.Mapper<List<OrgNodeDto>>(containsRepeatReference);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                list.Mapper<List<OrgNodeDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                list.Mapper<List<OrgNodeDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                list.Mapper<List<OrgNodeDto>>(containsRepeatReference);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestAutoMapperTree(List<OrgNode> list)
        {
            var config = new AutoMapper.MapperConfiguration(cfg =>
            {
                cfg.CreateMap<OrgNode, OrgNodeDto>();
            });
            var mapper = new AutoMapper.Mapper(config);
            mapper.Map<List<OrgNodeDto>>(list);

            var st = new Stopwatch();
            st.Start();
            mapper.Map<List<OrgNodeDto>>(list);
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                mapper.Map<List<OrgNodeDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                mapper.Map<List<OrgNodeDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                mapper.Map<List<OrgNodeDto>>(list);
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }

        static void TestJsonSerialTree(List<OrgNode> list)
        {
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<OrgNodeDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));

            var st = new Stopwatch();
            st.Start();
            Newtonsoft.Json.JsonConvert.DeserializeObject<List<OrgNodeDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            st.Stop();
            Console.WriteLine($"{"1 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 100; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OrgNodeDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"100 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (100 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 1000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OrgNodeDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"1000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (1000 * 1.0)} 毫秒".PadRight(30)}");

            st.Restart();
            for (int i = 0; i < 10000; i++)
            {
                Newtonsoft.Json.JsonConvert.DeserializeObject<List<OrgNodeDto>>(Newtonsoft.Json.JsonConvert.SerializeObject(list));
            }
            st.Stop();
            Console.WriteLine($"{"10000 次Mapper".PadRight(30)}{$"耗时: {st.ElapsedMilliseconds} 毫秒".PadRight(30)}{$"平均: {st.ElapsedMilliseconds / (10000 * 1.0)} 毫秒".PadRight(30)}");
        }
        #endregion

        #region 模型
        public enum EnumSex
        {
            Male, FeMale
        }
        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Addr { get; set; }
            public string IdentityNo { get; set; }
            public EnumSex Sex { get; set; }
            public DateTime Birth { get; set; }
            public string Description { get; set; }
            public int Age { get; set; }
            public string Nick { get; set; }
            public string QQ { get; set; }
            public string Email { get; set; }
            public string Phone { get; set; }
            public string WeiXin { get; set; }
            public string Picture { get; set; }
            public string Intro { get; set; }
            public double Score { get; set; }
            public List<string> Books { get; set; }
        }

        public class PersonDto
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Addr { get; set; }
            public string IdentityNo { get; set; }
            public EnumSex Sex { get; set; }
            public DateTime Birth { get; set; }
            public string Description { get; set; }
            public int Age { get; set; }
            public string Nick { get; set; }
            public string QQ { get; set; }
            public string Email { get; set; }
            public string Phone { get; set; }
            public string WeiXin { get; set; }
            public string Picture { get; set; }
            public string Intro { get; set; }
            public double Score { get; set; }
            public List<string> Books { get; set; }
        }
        public class Org
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Pwd { get; set; }
            public DateTime CreatetTime { get; set; }
            public bool? Active { get; set; }
            public int? ParentId { get; set; }
        }

        public class OrgDto
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public bool? Active { get; set; }
        }
        public class PersonExt : Person
        {
            public PersonExt Self { get; set; }
        }
        public class PersonExtDto : PersonDto
        {
            public PersonExtDto Self { get; set; }
        }
        public class Outer : Person
        {
            public Inner Inner { get; set; }
        }
        public class Inner
        {
            public int Id { get; set; }
            public int Age { get; set; }
            public double Score { get; set; }
            public string Name { get; set; }
            public string Addr { get; set; }
        }
        public class OuterDto : PersonDto
        {
            public InnerDto Inner { get; set; }
        }
        public class InnerDto
        {
            public int Id { get; set; }
            public int Age { get; set; }
            public double Score { get; set; }
            public string Name { get; set; }
            public string Addr { get; set; }
        }
        public class OrgNode : Org
        {
            public List<OrgNode> Children { get; set; }
        }

        public class OrgNodeDto : OrgDto
        {
            public List<OrgNodeDto> Children { get; set; }
        }
        #endregion
    }
}
